//
//  SIX_IAPHelper.m
//  sysg
//
//  Created by Cool.Cat on 14-5-13.
//
//

#import "SIX_IAPHelper.h"
#import "SIX_CCIOSHelper.h"

@interface SIX_IAPHelper()
    // private:
    // 真正提交购买请求
    - (void)BuyItemFinal:(NSString *)itemID;
@end

@implementation SIX_IAPHelper

- (id)init
{
    if (self=[super init])
    {
        bInited = FALSE;
        pCallbackUrl = [[NSString alloc] init];
        itemRequest = nil;
        myUserIdx = 0;
        myUserName = nil;
        myUserPass = nil;
        merchantID = 0;
        applicationID = 0;
        productID = 0;
        productName = nil;
        productItemPrice = 0;
        productItemPricePresent = 0;
        productExchangePrice = 0;
        productItemQuanitity = 0;
        productExchangeQuanitity = 0;
        productExchangeTotalFee = 0;
        productPayType = 0;
        orderID = [[NSString alloc] init];
        [orderID retain];
    }
    return self;
}

- (void)dealloc
{
    [pCallbackUrl release];
    [myUserName release];
    [myUserPass release];
    [productName release];
    [orderID release];
    [super dealloc];
}

// 初始化
- (BOOL)Initialization:(NSString *)pUrl userIdx:(long long)idx userName:(NSString *)N userPass:(NSString *)P mchID:(int)mchID appID:(int)appID
{
    if ([self canMakePurchases]==FALSE)
        return FALSE;
    if (bInited)
        return TRUE;
    pCallbackUrl = [NSString stringWithString:pUrl];
    [pCallbackUrl retain];
    myUserIdx = idx;
    myUserName = [NSString stringWithString:N];
    [myUserName retain];
    myUserPass = [NSString stringWithString:P];
    [myUserPass retain];
    merchantID = mchID;
    applicationID = appID;
    //NSLog(@"Initialization.pCallbackUrl[%@]",pCallbackUrl);
    // 添加事务监听事件
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    bInited = TRUE;
    return TRUE;
}

// 是否允许IAP
- (BOOL)canMakePurchases
{
    return [SKPaymentQueue canMakePayments];
}

// 请求商品(异步)
- (int)BuyItem:(int)itemID itemName:(NSString *)itemName itemPrice:(int)itemPrice itemPricePresent:(int)itemPricePresent exchangePrice:(int)exchangePrice itemQuanitity:(int)itemQuanitity exchangeQuanitity:(int)exchangeQuanitity exchangeTotalFee:(int)exchangeTotalFee payType:(int)payType
{
    // 用户有可能短时间内发起多次购买请求，由于itemRequest是异步的，所以后面多次释放就会造成冲突；
    // 原则上来说，用户必须等待上次购买请求返回明确的状态(成功/失败)后，才能再次发起下次的购买请求！
    // Cool.Cat
    
    // 如果上次有未决的购买请求
    if ([self UpdateLastPendingRequest]==FALSE)
    {
        NSLog(@"上次购买请求尚未完成！");
        // 则：通知应用层稍候再尝试发起购买请求
        return 0;
    }
    
    // save it~
    productID = itemID;
    productName = [NSString stringWithFormat:@"%@",itemName];
    [productName retain];
    productItemPrice = itemPrice;
    productItemPricePresent = itemPricePresent;
    productExchangePrice = exchangePrice;
    productItemQuanitity = itemQuanitity;
    productExchangeQuanitity = exchangeQuanitity;
    productExchangeTotalFee = exchangeTotalFee;
    productPayType = payType;
    
    NSSet *productIdentifiers = [NSSet setWithObject:itemName];
    itemRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    itemRequest.delegate = self;
    [itemRequest start];
    
    // req在回调中释放
    return 1;
}

// 服务器应答(回调)
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *products = response.products;
    if ([products count]<=0)
    {
        // 如果应答得到是错误的商品
        for (NSString *invalidProductId in response.invalidProductIdentifiers)
        {
            // 怎么做？
            NSLog(@"productsRequest.invalidProduct: %@",invalidProductId);
        }
        NSLog(@"----------------------------");
        NSLog(@"productsRequest.products.Nil");
        return;
    }
    
    SKProduct *pItem = [products firstObject];

    NSLog(@"商品名称: %@",pItem.localizedTitle);
    NSLog(@"商品描述: %@",pItem.localizedDescription);
    NSLog(@"商品单价: %@",pItem.price);
    NSLog(@"商品标识: %@",pItem.productIdentifier);
    
    SIX_CCIOSHelper::GetInstance()->OnIAPProcessed([pItem.productIdentifier UTF8String],[pItem.price intValue],[pItem.localizedTitle UTF8String],[pItem.localizedDescription UTF8String]);    
    
    // 正式提交购买请求
    [self BuyItemFinal:pItem.productIdentifier];
    
    // req在这里释放
    [itemRequest release];
}

// 网络请求异常较多，所以应在提交购买请求前，先处理上次未决的购买请求(防止掉单)
// Cool.Cat@2014-05-17
- (BOOL)UpdateLastPendingRequest
{
    NSArray *transactions = [SKPaymentQueue defaultQueue].transactions;
    if (transactions.count==0)
        return TRUE;

    SKPaymentTransaction *transaction = [transactions lastObject];
    
    // 处理上次的请求结果，可能是上次用户未等请求完成就完毕app或异常退出导致的掉单
    // Cool.Cat
    if (transaction.transactionState==SKPaymentTransactionStatePurchased ||
        transaction.transactionState==SKPaymentTransactionStateRestored)
    {
        NSLog(@"上次购买请求已完成，正在完成处理 ...");
        [self completeTransaction:transaction];
        return FALSE;
    }
    
    // -----------------------------------------------------------
    // 如果请求队列还有以下两种状态的请求，且并未从队列中移除，则：返回未决状态
    // SKPaymentTransactionStatePurchasing
    // SKPaymentTransactionStateFailed
    // -----------------------------------------------------------
    // Cool.Cat
    return FALSE;
}

// 提交购买请求
- (void)BuyItemFinal:(NSString *)itemID
{
    NSLog(@"BuyItemFinal[%@]",itemID);
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:itemID];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

// -------------------------------------------------
// 后端二次验证(同步)
// POST Format:
// -------------------------------------------------
// C=UserIdx,UserName,UserPass,merchantID,..,Receipt
// N=RND(x,y)
// F=Hash(MD5(C,N)),N,C
// -------------------------------------------------
// Cool.Cat@2014-05-16
- (BOOL)OnReceiptVerify:(NSString *)productId receipt:(NSData *)transactionReceipt
{
    NSString *pReceipt = [transactionReceipt base64Encoding];
//    NSLog(@"OnReceiptVerify.myUserIdx[%lld]",myUserIdx);
//    NSLog(@"OnReceiptVerify.myUserName[%@]",myUserName);
//    NSLog(@"OnReceiptVerify.myUserPass[%@]",myUserPass);
//    NSLog(@"OnReceiptVerify.pCallbackUrl[%@]",pCallbackUrl);
//    NSLog(@"OnReceiptVerify.merchantID[%d]",merchantID);
//    NSLog(@"OnReceiptVerify.applicationID[%d]",applicationID);
//    NSLog(@"OnReceiptVerify.productId[%d]",productID);
//    NSLog(@"OnReceiptVerify.productName[%@]",productName);
//    NSLog(@"OnReceiptVerify.productItemPrice[%d]",productItemPrice);
//    NSLog(@"OnReceiptVerify.productItemPricePresent[%d]",productItemPricePresent);
//    NSLog(@"OnReceiptVerify.productExchangePrice[%d]",productExchangePrice);
//    NSLog(@"OnReceiptVerify.productItemQuanitity[%d]",productItemQuanitity);
//    NSLog(@"OnReceiptVerify.productExchangeQuanitity[%d]",productExchangeQuanitity);
//    NSLog(@"OnReceiptVerify.productExchangeTotalFee[%d]",productExchangeTotalFee);
//    NSLog(@"OnReceiptVerify.productPayType[%d]",productPayType);
//    NSLog(@"OnReceiptVerify.pReceipt[%@]",pReceipt);
    
    NSString *pDataOgi = [NSString stringWithFormat:@"%lld,%@,%@,%d,%d,%d,%@,%d,%d,%d,%d,%d,%d,%d,%@",
                          myUserIdx,
                          myUserName,
                          myUserPass,
                          merchantID,
                          applicationID,
                          productID,
                          productName,
                          productItemPrice,
                          productItemPricePresent,
                          productExchangePrice,
                          productItemQuanitity,
                          productExchangeQuanitity,
                          productExchangeTotalFee,
                          productPayType,
                          pReceipt];
    unsigned int N= [self RNDNUM:16 max:32];
    NSString *pMD5 = [self MD5:pDataOgi rndNum:N];
    NSString *pSHA1 = [self SHA1:pMD5];
    NSString *pPostData = [NSString stringWithFormat:@"F=%@,%u,%@",pSHA1,N,pDataOgi];
    //NSLog(@"OnReceiptVerify.N[%d].pMD5[%@].pSHA1[%@].pPostData[%@]",N,pMD5,pSHA1,pPostData);
    
    NSMutableURLRequest *pRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:pCallbackUrl]];
    [pRequest setHTTPMethod:@"POST"];
    [pRequest setHTTPBody:[pPostData dataUsingEncoding:NSUTF8StringEncoding]];
    [pRequest addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
//    [pRequest setValue:[NSString stringWithFormat:@"%d",[pData length]] forKeyPath:@"Content-Length"];
    
    NSError *pError = nil;
    NSURLResponse *pUrlResponse = nil;
    NSData *pDataBack = [NSURLConnection sendSynchronousRequest:pRequest returningResponse:&pUrlResponse error:&pError];
    
    //NSLog(@"OnReceiptVerify.pDataBack[%@]",pDataBack);
    
    if (pDataBack==nil)
    {
        NSLog(@"OnReceiptVerify.pDataBack.Nil");
        return FALSE;
    }
    
    // catch error!
    if (pError!=nil)
    {
        NSLog(@"OnReceiptVerify.pError[%d][%@]",[pError code],[pError description]);
        return FALSE;
    }
    
    NSString *pResponse = [[NSString alloc] initWithData:pDataBack encoding:NSUTF8StringEncoding];
    if (pResponse==nil)
    {
        NSLog(@"OnReceiptVerify.pResponse.Nil");
        return FALSE;
    }
    NSLog(@"OnReceiptVerify.pResponse[%@]",pResponse);
    
    // 1、客户端有可能模拟破解购买请求，所以这里只有接收我们后端二次校验服务器返回status=0，才认为是真正购买成功的；
    // 2、其他由于网络环境、用户使用强购插件等导致的status!=0，一律判定购买失败！
    // 3、界面要给与必要的提示信息，如：购买失败，请联系客服等。
    NSArray *pArray = [pResponse componentsSeparatedByString:@","];
    if ([pArray count]!=2)
    {
        NSLog(@"OnReceiptVerify.pResponse.count[%d].invalid",[pArray count]);
        return FALSE;
    }
    if ([orderID retainCount]>1)
        [orderID release];
    orderID = [NSString stringWithString:[pArray objectAtIndex:0]];
    [orderID retain];
    NSInteger status = [[pArray objectAtIndex:1] integerValue];
    NSLog(@"OnReceiptVerify.orderID[%@].status[%d]",orderID,status);
    switch (status)
    {
            // 验证成功
        case 0:
        {
            return TRUE;
        }
            // AppStore无法识别提交的json
        case 21000:
        {
            break;
        }
            // receipt数据不正确
        case 21002:
        {
            break;
        }
            // receipt无法通过验证
        case 21003:
        {
            break;
        }
            // receipt中的校验信息与AppID不一致
        case 21004:
        {
            break;
        }
            // receipt官方校验服务器不可用
        case 21005:
        {
            break;
        }
            // receipt合法，但是订阅已经过期
        case 21006:
        {
            break;
        }
            // receipt为测试环境数据，但是发送到了生产环境的校验服务器
        case 21007:
        {
            break;
        }
            // receipt为生产环境数据，但是发送到了测试环境的校验服务器
        case 21008:
        {
            break;
        }
    }
    return FALSE;
}

// 事务结束
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
    // 从请求队列中移除事务
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    
    if (wasSuccessful)
    {
        // 成功
        SIX_CCIOSHelper::GetInstance()->OnIAPSuccessed(
                                                       [transaction.transactionIdentifier UTF8String],
                                                       [transaction.payment.productIdentifier UTF8String],
                                                       transaction.payment.quantity,
                                                       [transaction.originalTransaction.payment.productIdentifier UTF8String],
                                                       transaction.originalTransaction.payment.quantity,
                                                       [orderID UTF8String]
                                                );
    }
    else
    {
        // 失败
        SIX_CCIOSHelper::GetInstance()->OnIAPFailed(
                                                    [transaction.transactionIdentifier UTF8String],
                                                    [transaction.payment.productIdentifier UTF8String],
                                                    transaction.payment.quantity,
                                                    [transaction.originalTransaction.payment.productIdentifier UTF8String],
                                                    transaction.originalTransaction.payment.quantity,
                                                    [orderID UTF8String],
                                                    transaction.error.code,
                                                    [transaction.error.description UTF8String]
                                                );
    }
}

// 事务成功回调
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    NSLog(@"completeTransaction.productIdentifier[%@]",transaction.payment.productIdentifier);
    // 二次验证
    BOOL status = [self OnReceiptVerify:transaction.payment.productIdentifier receipt:transaction.transactionReceipt];
    // 善后～
    [self finishTransaction:transaction wasSuccessful:status];
}

// 事务恢复回调
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
    NSLog(@"restoreTransaction.productIdentifier[%@]",transaction.originalTransaction.payment.productIdentifier);
    // 二次验证
    BOOL status = [self OnReceiptVerify:transaction.originalTransaction.payment.productIdentifier receipt:transaction.originalTransaction.transactionReceipt];
    // 善后～
    [self finishTransaction:transaction wasSuccessful:status];
}

// 事务失败回调
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    // 如果用户手工取消支付了
    if (transaction.error.code == SKErrorPaymentCancelled)
    {
        NSLog(@"failedTransaction.productIdentifier[%@].user choose cancel!",transaction.payment.productIdentifier);
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        SIX_CCIOSHelper::GetInstance()->OnIAPCancel(
                                                    [transaction.transactionIdentifier UTF8String],
                                                    [transaction.payment.productIdentifier UTF8String],
                                                    transaction.payment.quantity,
                                                    [transaction.originalTransaction.payment.productIdentifier UTF8String],
                                                    transaction.originalTransaction.payment.quantity
                                                );
    }
    // 否则说明交易出现异常了
    else
    {
        NSLog(@"failedTransaction.productIdentifier[%@].errCode[%d]",transaction.payment.productIdentifier,transaction.error.code);
        [self finishTransaction:transaction wasSuccessful:NO];
    }
}

// Asynchronous.  Start the given downloads (SKDownload).
- (void)startDownloads:(NSArray *)downloads
{
    NSLog(@"startDownloads");
}

// Asynchronous.  Pause/resume downloads (SKDownload).
- (void)pauseDownloads:(NSArray *)downloads
{
    NSLog(@"pauseDownloads");
}

- (void)resumeDownloads:(NSArray *)downloads
{
    NSLog(@"resumeDownloads");
}

// Asynchronous.  Cancel downloads (SKDownload)
- (void)cancelDownloads:(NSArray *)downloads
{
    NSLog(@"cancelDownloads");
}

/*
SKPaymentTransactionObserver
*/
// 事务更新
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
                // 成功
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
                // 恢复
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
                // 失败
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            default:
                break;
        }
    }
}

// Sent when transactions are removed from the queue (via finishTransaction:).
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
    NSLog(@"removedTransactions.count[%d]",transactions.count);
    // 购买请求删除后，要在这里通知上层
    // Cool.Cat
    for (int i=0;i<transactions.count;i++)
    {
        SKPaymentTransaction *transaction = [transactions objectAtIndex:i];
        SIX_CCIOSHelper::GetInstance()->OnIAPCompleted(
                                                       [transaction.transactionIdentifier UTF8String],
                                                       [transaction.payment.productIdentifier UTF8String],
                                                       transaction.payment.quantity,
                                                       [transaction.originalTransaction.payment.productIdentifier UTF8String],
                                                       transaction.originalTransaction.payment.quantity
                                                    );
    }
}

// Sent when an error is encountered while adding transactions from the user's purchase history back to the queue.
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
    NSLog(@"restoreCompletedTransactionsFailedWithError.error[%d]=[%@]",[error code],[error description]);
}

// Sent when all transactions from the user's purchase history have successfully been added back to the queue.
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"paymentQueueRestoreCompletedTransactionsFinished");
}

// Sent when the download state has changed.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads
{
    NSLog(@"updatedDownloads");
}

// -------------------
// 以下为加密辅助函数
// -------------------
// Cool.Cat@2014-05-17
// -------------------
- (unsigned int)RNDNUM:(int)min max:(int)max
{
    unsigned int rndnum = 0;
    rndnum = arc4random()%(max-min+1)+min;
    if (rndnum<min)
        rndnum = min;
    return rndnum;
}

- (NSString*)SHA1:(NSString*)src
{
    const char *cstr = [src cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:src.length];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH*2];
    
    CC_SHA1(data.bytes,data.length,digest);
    
    for(int i=0;i<CC_SHA1_DIGEST_LENGTH;i++)
    {
        [output appendFormat:@"%02X",digest[i]];
    }
    return output;
}

- (NSString *)MD5:(NSString *)src rndNum:(unsigned int)rnd
{
    const char *cStr = [src UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
    
    CC_MD5( cStr, strlen(cStr), digest);
    
    for(int i=0;i<CC_MD5_DIGEST_LENGTH;i++)
    {
        [output appendFormat:@"%02X",digest[i]];
    }
    
    NSMutableString *pMD5 = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
    [pMD5 appendFormat:@"%s",[output UTF8String]];
    for (unsigned int i=0;i<(rnd-1);i++)
    {
        [pMD5 uppercaseString];
        //NSLog(@"pMD5[%u]=%@",i,pMD5);
        CC_MD5([pMD5 UTF8String],CC_MD5_DIGEST_LENGTH*2,digest);
        [pMD5 setString:@""];
        //NSLog(@"digest=[%02X/%02X/%02X]",digest[0],digest[1],digest[2]);
        for(int i=0;i<CC_MD5_DIGEST_LENGTH;i++)
        {
            [pMD5 appendFormat:@"%02X",digest[i]];
        }
    }
    return pMD5;
}
@end